#include "messageshowarea.h"
#include "debug.h"
#include "mainwidget.h"
#include "model/datacenter.h"

MessageShowArea::MessageShowArea()
{
    // 1. 初始化基本属性
    this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    this->setWidgetResizable(true);
    // 设置滚动条样式
    this->verticalScrollBar()->setStyleSheet(
        "QScrollBar:vertical { width: 2px; background-color: rgb(240, 240, 240); }");
    this->horizontalScrollBar()->setStyleSheet("QScrollBar:horizontal { height: 0;}");
    this->setStyleSheet("QScrollArea { border: none; }");

    // 2.创建 container 作为包含内部元素的容器
    _container = new QWidget();
    this->setWidget(_container);

    // 3. 给 container 添加布局管理器
    QVBoxLayout *layout = new QVBoxLayout();
    layout->setSpacing(0);
    layout->setContentsMargins(0, 0, 0, 0);
    _container->setLayout(layout);

    // 添加 构造测试数据
#if TEST_UI
    model::UserInfo userInfo;
    userInfo.userId      = QString::number(1000);
    userInfo.nickname    = "张三";
    userInfo.description = "从今天开始认真敲代码";
    userInfo.avatar      = QIcon(":/resource/image/defaultAvatar.png");
    userInfo.phone       = "12345678901";
    Message message =
        Message::makeMessage(model::TEXT_TYPE, "", userInfo,
                             QString("这是一条测试消息这是一条测试消息这是一条测试消息这是一条测试消息这"
                                     "是一条测试消息这是一条测试消息这是一条测试消息这是一条测试消息这是一条测试消息")
                                 .toUtf8(),
                             "");
    this->addMessage(false, message);

    for (int i = 1; i <= 30; ++i)
    {
        model::UserInfo userInfo;
        userInfo.userId      = QString::number(1000 + i);
        userInfo.nickname    = "张三" + QString::number(i);
        userInfo.description = "从今天开始认真敲代码";
        userInfo.avatar      = QIcon(":/resource/image/defaultAvatar.png");
        userInfo.phone       = "18612345678";
        Message message      = Message::makeMessage(model::TEXT_TYPE, "", userInfo,
                                                    (QString("这是一条测试消息") + QString::number(i)).toUtf8(), "");
        this->addMessage(true, message);
    }
#endif
};

void MessageShowArea::addMessage(bool isLeft, const Message &message)
{
    // 构造 MessageItem，添加到布局管理器中
    MessageItem *messageItem = MessageItem::makeMessageItem(isLeft, message);
    _container->layout()->addWidget(messageItem);
}

void MessageShowArea::addFrontMessage(bool isLeft, const Message &message)
{
    MessageItem *messageItem = MessageItem::makeMessageItem(isLeft, message);
    QVBoxLayout *layout      = dynamic_cast<QVBoxLayout *>(_container->layout());
    layout->insertWidget(0, messageItem);
}

void MessageShowArea::clear()
{
    // 遍历布局管理器，删除里面的元素
    QLayout *layout = _container->layout();
    for (int i = layout->count() - 1; i >= 0; i--)
    {
        QLayoutItem *item = layout->takeAt(i);
        if (item != nullptr && item->widget() != nullptr)
        {
            delete item->widget();
        }
    }
}

void MessageShowArea::scrollToEnd()
{
    // 拿到滚动区域中的滚动条
    // 为了达到延时的效果，使滚动在界面完成渲染后再设置
    QTimer *timer = new QTimer();
    connect(timer, &QTimer::timeout, this,
            [=]()
            {
                // 获取到垂直滚动条的最大值
                int maxValue = this->verticalScrollBar()->maximum();
                // 设置滚动条的滚动位置
                this->verticalScrollBar()->setValue(maxValue);

                timer->stop();
                timer->deleteLater();
            });
    timer->start(500);
}

MessageItem::MessageItem(bool isLeft) {}

MessageItem *MessageItem::makeMessageItem(bool isLeft, const Message &message)
{
    // 1. 创建对象和布局管理器
    MessageItem *messageItem = new MessageItem(isLeft);
    QGridLayout *layout      = new QGridLayout();
    layout->setContentsMargins(30, 10, 40, 0);
    layout->setSpacing(10);
    // 这个 MessageItem 最低不能低于 100
    messageItem->setLayout(layout);

    // 2.创建头像
    QPushButton *avatarBtn = new QPushButton();
    avatarBtn->setFixedSize(40, 40);
    avatarBtn->setIconSize(QSize(40, 40));
    avatarBtn->setIcon(message.sender.avatar);
    avatarBtn->setStyleSheet("QPushButton { border: none;}");
    if (isLeft)
    {
        layout->addWidget(avatarBtn, 0, 0, 2, 1, Qt::AlignTop | Qt::AlignLeft);
    }
    else
    {
        layout->addWidget(avatarBtn, 0, 1, 2, 1, Qt::AlignTop | Qt::AlignLeft);
    }

    // 3. 创建名字和时间
    QLabel *nameLabel = new QLabel();
    nameLabel->setText(message.sender.nickname + "|" + message.time);
    nameLabel->setAlignment(Qt::AlignBottom);
    nameLabel->setStyleSheet("QLabel { font-size: 12px; color: rgb(178, 178, 178); }");
    if (isLeft)
    {
        layout->addWidget(nameLabel, 0, 1);
    }
    else
    {
        layout->addWidget(nameLabel, 0, 0, Qt::AlignRight);
    }

    // 4. 创建消息体
    QWidget *contentWidget = nullptr;
    switch (message.messageType)
    {
        case model::TEXT_TYPE:
            contentWidget = makeTextMessageItem(isLeft, message.content);
            break;
        case model::IMAGE_TYPE:
            contentWidget = makeImageMessageItem(isLeft, message.fileId, message.content);
            break;
        case model::FILE_TYPE:
            contentWidget = makeFileMessageItem(isLeft, message);
            break;
        case model::SPEECH_TYPE:
            contentWidget = makeSpeechMessageItem(isLeft, message);
            break;
        default:
            LOG() << "错误的消息类型！messageType=" << message.messageType;
    }
    if (isLeft)
    {
        layout->addWidget(contentWidget, 1, 1);
    }
    else
    {
        layout->addWidget(contentWidget, 1, 0);
    }

    // 6. 当用户修改了昵称时，同步修改此处的用户昵称
    if (!isLeft)
    {
        // 只针对右侧消息
        model::DataCenter *dataCenter = model::DataCenter::getInstance();
        connect(dataCenter, &model::DataCenter::changeNicknameDone, messageItem,
                [=]() { nameLabel->setText(dataCenter->getMyself()->nickname + "|" + message.time); });

        // 当用户修改头像时，同步新头像
        connect(dataCenter, &model::DataCenter::changeAvatarDone, messageItem,
                [=]()
                {
                    model::UserInfo *myself = dataCenter->getMyself();
                    avatarBtn->setIcon(myself->avatar);
                });
    }
    return messageItem;
}

QWidget *MessageItem::makeTextMessageItem(bool isLeft, const QString &text)
{
    MessageContentLabel *messageContentLabel =
        new MessageContentLabel(text, isLeft, model::TEXT_TYPE, "", QByteArray());
    return messageContentLabel;
}

QWidget *MessageItem::makeImageMessageItem(bool isLeft, const QString &fileId, const QByteArray &content)
{
    MessageImageLabel *messageImageLabel = new MessageImageLabel(fileId, content, isLeft);
    return messageImageLabel;
}

QWidget *MessageItem::makeFileMessageItem(bool isLeft, const Message &message)
{
    MessageContentLabel *messageFileLabel = new MessageContentLabel(
        "[文件]" + message.fileName, isLeft, message.messageType, message.fileId, message.content);
    return messageFileLabel;
}

QWidget *MessageItem::makeSpeechMessageItem(bool isLeft, const Message &message)
{
    MessageContentLabel *messageSpeechLabel =
        new MessageContentLabel("[语音]", isLeft, message.messageType, message.fileId, message.content);
    return messageSpeechLabel;
}

MessageContentLabel::MessageContentLabel(const QString &text, bool isLeft, model::MessageType messageType,
                                         const QString &fileId, const QByteArray content)
    : _isLeft(isLeft), _messageType(messageType), _fileId(fileId), _content(content)
{
    this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

    QFont font;
    font.setFamily("微软雅黑");
    font.setPixelSize(16);

    _label = new QLabel(this);
    _label->setText(text);
    _label->setFont(font);
    _label->setAlignment(Qt::AlignVCenter | Qt::AlignLeft);
    _label->setWordWrap(true); // 设置文本自动换行
    _label->setStyleSheet("QLabel { padding: 0 10px; line-height: 1.2; background-color: transparent; }");
}

// 这个函数在控件显示时自动调用
void MessageContentLabel::paintEvent(QPaintEvent *event)
{
    (void) event;

    // 1. 获取父元素的宽度
    QObject *object = this->parent();
    if (!object->isWidgetType())
    {
        // 当前父元素不是预期的 QWidget 时，不需要进行后续的绘制操作
        return;
    }
    QWidget *parent = dynamic_cast<QWidget *>(object);
    int width       = parent->width() * 0.6;

    // 2. 计算当前文本，如果是一行放置，需要多宽
    QFontMetrics metrics(_label->font());
    int totalWidth = metrics.horizontalAdvance(_label->text()); // 获取 label 的文本占多少个宽度

    // 3. 计算出此处的行数是多少
    int rows = (totalWidth / (width - 40)) + 1; // 40 表示文本左右各有 20px 的边距
    if (rows == 1)
    {
        width = totalWidth + 40;
    }

    // 4. 根据行数，计算得到高度
    int height = rows * (_label->font().pixelSize() * 1.2) + 20; // 20 表示上下各有 10px 的边距

    // 5. 绘制圆角矩形和箭头
    QPainter painter(this);
    QPainterPath path;
    // 设置抗锯齿
    painter.setRenderHint(QPainter::Antialiasing);
    if (_isLeft)
    {
        painter.setPen(QPen(QColor(255, 255, 255)));
        painter.setBrush(QColor(255, 255, 255));

        // 绘制圆角矩形
        painter.drawRoundedRect(10, 0, width, height, 10, 10);
        // 绘制箭头
        path.moveTo(10, 15);
        path.lineTo(0, 20);
        path.lineTo(10, 25);
        path.closeSubpath();    // 绘制的线形成闭合的多边形，才能使用 Brush 填充颜色
        painter.drawPath(path); // 绘制操作

        _label->setGeometry(10, 0, width, height);
    }
    else
    {
        painter.setPen(QPen(QColor(149, 236, 105))); // 右侧消息绿色泡泡
        painter.setBrush(QColor(149, 236, 105));

        // 右侧消息的位置从左边定位
        //  右侧消息的左侧边位置
        int leftPos = this->width() - width - 10; // 10 用于容纳箭头的宽度
        // 右侧消息的右侧边位置
        int rightPos = this->width() - 10;
        // 绘制圆角矩形
        painter.drawRoundedRect(leftPos, 0, width, height, 10, 10);
        // 绘制箭头
        path.moveTo(rightPos, 15);
        path.lineTo(rightPos + 10, 20);
        path.lineTo(rightPos, 25);
        path.closeSubpath();    // 绘制的线形成闭合的多边形，才能使用 Brush 填充颜色
        painter.drawPath(path); // 绘制操作

        _label->setGeometry(leftPos, 0, width, height);
    }

    // 6. 重新设置父元素的高度，确保父元素足够高，能够容纳以上绘制的消息显示的区域
    parent->setFixedHeight(height + 50);
}

////////////////////////////////////////////////////////
/// 创建类表示 "图片消息" 正文部分
////////////////////////////////////////////////////////
MessageImageLabel::MessageImageLabel(const QString &fileId, const QByteArray &content, bool isLeft)
    : _fileId(fileId), _content(content), _isLeft(isLeft)
{
    this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

    _imageBtn = new QPushButton(this);
    _imageBtn->setStyleSheet("QPushButton {border: none;} ");
}
